From c821d809f6c56affe40aea94c2253304b51b04c7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 31 Dec 2018 12:53:21 +0100 Subject: [PATCH] Change ACME client to acme.sh --- .gitignore | 1 + .travis.yml | 3 +- Dockerfile | 17 ++- app/entrypoint.sh | 36 +++-- app/functions.sh | 19 +-- app/letsencrypt_service | 154 +++++++--------------- app/letsencrypt_service_data.tmpl | 6 +- install_acme.sh | 26 ++++ install_simp_le.sh | 30 ----- test/setup/setup-boulder.sh | 4 + test/tests/certs_san/expected-std-out.txt | 2 +- test/tests/certs_san/run.sh | 6 +- test/tests/certs_single/run.sh | 2 +- test/tests/certs_single_domain/run.sh | 4 +- test/tests/certs_standalone/run.sh | 2 +- test/tests/container_restart/run.sh | 2 +- test/tests/force_renew/run.sh | 2 +- test/tests/permissions_custom/run.sh | 13 +- test/tests/permissions_default/run.sh | 13 +- test/tests/symlinks/run.sh | 4 +- test/tests/test-functions.sh | 2 +- 21 files changed, 145 insertions(+), 203 deletions(-) create mode 100755 install_acme.sh delete mode 100755 install_simp_le.sh diff --git a/.gitignore b/.gitignore index df3ba2b..08ef588 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ certs/ conf.d/ data/ vhost.d/ +.vscode # tests go/ diff --git a/.travis.yml b/.travis.yml index b602183..eadb361 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,7 @@ before_install: install: - docker build -t "$IMAGE" . - docker inspect "$IMAGE" - - docker run --rm "$IMAGE" simp_le --version - - docker run --rm "$IMAGE" simp_le -v --test + - docker run --rm "$IMAGE" acme.sh --version - docker images before_script: diff --git a/Dockerfile b/Dockerfile index 2d2b375..afb78d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,32 +21,35 @@ FROM alpine:3.11 LABEL maintainer="Yves Blusseau <90z7oey02@sneakemail.com> (@blusseau)" -ENV DEBUG=false \ - DOCKER_HOST=unix:///var/run/docker.sock +ENV DOCKER_HOST=unix:///var/run/docker.sock \ + PATH=$PATH:/app # Install packages required by the image RUN apk add --update \ bash \ - ca-certificates \ coreutils \ curl \ jq \ + netcat-openbsd \ openssl \ + socat \ && rm /var/cache/apk/* # Install docker-gen from build stage COPY --from=go-builder /go/src/github.com/jwilder/docker-gen/docker-gen /usr/local/bin/ # Install simp_le -COPY /install_simp_le.sh /app/install_simp_le.sh -RUN chmod +rx /app/install_simp_le.sh \ +COPY /install_acme.sh /app/install_acme.sh +RUN chmod +rx /app/install_acme.sh \ && sync \ - && /app/install_simp_le.sh \ - && rm -f /app/install_simp_le.sh + && /app/install_acme.sh \ + && rm -f /app/install_acme.sh COPY /app/ /app/ WORKDIR /app +VOLUME ["/etc/acme.sh", "/etc/nginx/certs"] + ENTRYPOINT [ "/bin/bash", "/app/entrypoint.sh" ] CMD [ "/bin/bash", "/app/start.sh" ] diff --git a/app/entrypoint.sh b/app/entrypoint.sh index bb936ce..14b8e3e 100755 --- a/app/entrypoint.sh +++ b/app/entrypoint.sh @@ -4,7 +4,6 @@ set -u # shellcheck source=functions.sh source /app/functions.sh -DEBUG="$(lc "$DEBUG")" function check_deprecated_env_var { if [[ -n "${ACME_TOS_HASH:-}" ]]; then @@ -109,7 +108,7 @@ function check_default_cert_key { # than 3 months / 7776000 seconds (60 x 60 x 24 x 30 x 3). check_cert_min_validity /etc/nginx/certs/default.crt 7776000 cert_validity=$? - [[ "$DEBUG" == true ]] && echo "Debug: a default certificate with $default_cert_cn is present." + [[ "$DEBUG" == 1 ]] && echo "Debug: a default certificate with $default_cert_cn is present." fi # Create a default cert and private key if: @@ -126,23 +125,35 @@ function check_default_cert_key { && mv /etc/nginx/certs/default.key.new /etc/nginx/certs/default.key \ && mv /etc/nginx/certs/default.crt.new /etc/nginx/certs/default.crt echo "Info: a default key and certificate have been created at /etc/nginx/certs/default.key and /etc/nginx/certs/default.crt." - elif [[ "$DEBUG" == true && "${default_cert_cn:-}" =~ $cn ]]; then + elif [[ "$DEBUG" == 1 && "${default_cert_cn:-}" =~ $cn ]]; then echo "Debug: the self generated default certificate is still valid for more than three months. Skipping default certificate creation." - elif [[ "$DEBUG" == true ]]; then + elif [[ "$DEBUG" == 1 ]]; then echo "Debug: the default certificate is user provided. Skipping default certificate creation." fi set_ownership_and_permissions "/etc/nginx/certs/default.key" set_ownership_and_permissions "/etc/nginx/certs/default.crt" } -if [[ "$*" == "/bin/bash /app/start.sh" ]]; then - acmev1_r='acme-(v01\|staging)\.api\.letsencrypt\.org' - if [[ "${ACME_CA_URI:-}" =~ $acmev1_r ]]; then - echo "Error: the ACME v1 API is no longer supported by simp_le." - echo "See https://github.com/zenhack/simp_le/pull/119" - echo "Please use one of Let's Encrypt ACME v2 endpoints instead." - exit 1 +function configure_default_email { + # Configure the email used by the default config + [[ -d /etc/acme.sh/default ]] || mkdir -p /etc/acme.sh/default + if [[ -f /etc/acme.sh/default/account.conf ]]; then + if [[ -f /etc/acme.sh/default/ca/acme-v01.api.letsencrypt.org/account.json ]]; then + acme.sh --update-account --accountemail "${DEFAULT_EMAIL:-}" + return 0 + elif grep -q ACCOUNT_EMAIL /etc/acme.sh/default/account.conf; then + if grep -q "${DEFAULT_EMAIL:-}" /etc/acme.sh/default/account.conf; then + return 0 + else + sed -i "s/^ACCOUNT_EMAIL=.*$/ACCOUNT_EMAIL='${DEFAULT_EMAIL:-}'/g" /etc/acme.sh/default/account.conf + return 0 + fi + fi fi + echo "ACCOUNT_EMAIL='${DEFAULT_EMAIL:-}'" >> /etc/acme.sh/default/account.conf +} + +if [[ "$*" == "/bin/bash /app/start.sh" ]]; then check_docker_socket if [[ -z "$(get_nginx_proxy_container)" ]]; then echo "Error: can't get nginx-proxy container ID !" >&2 @@ -160,12 +171,13 @@ if [[ "$*" == "/bin/bash /app/start.sh" ]]; then fi check_writable_directory '/etc/nginx/certs' check_writable_directory '/etc/nginx/vhost.d' + check_writable_directory '/etc/acme.sh' check_writable_directory '/usr/share/nginx/html' [[ -f /app/letsencrypt_user_data ]] && check_writable_directory '/etc/nginx/conf.d' - check_deprecated_env_var check_default_cert_key check_dh_group reload_nginx + [[ -n ${DEFAULT_EMAIL:-} ]] && configure_default_email fi exec "$@" diff --git a/app/functions.sh b/app/functions.sh index 68fab2f..30ff533 100644 --- a/app/functions.sh +++ b/app/functions.sh @@ -5,7 +5,10 @@ function lc { echo "${@,,}" } -DEBUG="$(lc "$DEBUG")" +DEBUG="$(lc "${DEBUG:-}")" +if [[ "$DEBUG" == true ]]; then + DEBUG=1 && export DEBUG +fi [[ -z "${VHOST_DIR:-}" ]] && \ declare -r VHOST_DIR=/etc/nginx/vhost.d @@ -325,7 +328,7 @@ function set_ownership_and_permissions { return 1 fi - [[ "$DEBUG" == true ]] && echo "Debug: checking $path ownership and permissions." + [[ "$DEBUG" == 1 ]] && echo "Debug: checking $path ownership and permissions." # Find the user numeric ID if the FILES_UID environment variable isn't numeric. if [[ "$user" =~ ^[0-9]+$ ]]; then @@ -334,7 +337,7 @@ function set_ownership_and_permissions { elif id -u "$user" > /dev/null 2>&1; then # Convert the user name to numeric ID local user_num; user_num="$(id -u "$user")" - [[ "$DEBUG" == true ]] && echo "Debug: numeric ID of user $user is $user_num." + [[ "$DEBUG" == 1 ]] && echo "Debug: numeric ID of user $user is $user_num." else echo "Warning: user $user not found in the container, please use a numeric user ID instead of a user name. Skipping ownership and permissions check." return 1 @@ -347,7 +350,7 @@ function set_ownership_and_permissions { elif getent group "$group" > /dev/null 2>&1; then # Convert the group name to numeric ID local group_num; group_num="$(getent group "$group" | awk -F ':' '{print $3}')" - [[ "$DEBUG" == true ]] && echo "Debug: numeric ID of group $group is $group_num." + [[ "$DEBUG" == 1 ]] && echo "Debug: numeric ID of group $group is $group_num." else echo "Warning: group $group not found in the container, please use a numeric group ID instead of a group name. Skipping ownership and permissions check." return 1 @@ -356,7 +359,7 @@ function set_ownership_and_permissions { # Check and modify ownership if required. if [[ -e "$path" ]]; then if [[ "$(stat -c %u:%g "$path" )" != "$user_num:$group_num" ]]; then - [[ "$DEBUG" == true ]] && echo "Debug: setting $path ownership to $user:$group." + [[ "$DEBUG" == 1 ]] && echo "Debug: setting $path ownership to $user:$group." if [[ -L "$path" ]]; then chown -h "$user_num:$group_num" "$path" else @@ -366,7 +369,7 @@ function set_ownership_and_permissions { # If the path is a folder, check and modify permissions if required. if [[ -d "$path" ]]; then if [[ "$(stat -c %a "$path")" != "$d_perms" ]]; then - [[ "$DEBUG" == true ]] && echo "Debug: setting $path permissions to $d_perms." + [[ "$DEBUG" == 1 ]] && echo "Debug: setting $path permissions to $d_perms." chmod "$d_perms" "$path" fi # If the path is a file, check and modify permissions if required. @@ -374,13 +377,13 @@ function set_ownership_and_permissions { # Use different permissions for private files (private keys and ACME account files) ... if [[ "$path" =~ ^.*(default\.key|key\.pem|\.json)$ ]]; then if [[ "$(stat -c %a "$path")" != "$f_perms" ]]; then - [[ "$DEBUG" == true ]] && echo "Debug: setting $path permissions to $f_perms." + [[ "$DEBUG" == 1 ]] && echo "Debug: setting $path permissions to $f_perms." chmod "$f_perms" "$path" fi # ... and for public files (certificates, chains, fullchains, DH parameters). else if [[ "$(stat -c %a "$path")" != "644" ]]; then - [[ "$DEBUG" == true ]] && echo "Debug: setting $path permissions to 644." + [[ "$DEBUG" == 1 ]] && echo "Debug: setting $path permissions to 644." chmod "644" "$path" fi fi diff --git a/app/letsencrypt_service b/app/letsencrypt_service index 1b6f443..6040716 100755 --- a/app/letsencrypt_service +++ b/app/letsencrypt_service @@ -2,20 +2,18 @@ # shellcheck source=functions.sh source /app/functions.sh -DEBUG="$(lc "$DEBUG")" seconds_to_wait=3600 ACME_CA_URI="${ACME_CA_URI:-https://acme-v02.api.letsencrypt.org/directory}" -DEFAULT_KEY_SIZE=4096 -REUSE_ACCOUNT_KEYS="$(lc "${REUSE_ACCOUNT_KEYS:-true}")" -REUSE_PRIVATE_KEYS="$(lc "${REUSE_PRIVATE_KEYS:-false}")" +DEFAULT_KEY_SIZE="${DEFAULT_KEY_SIZE:-4096}" +RENEW_PRIVATE_KEYS="$(lc "${RENEW_PRIVATE_KEYS:-true}")" function create_link { local -r source=${1?missing source argument} local -r target=${2?missing target argument} if [[ -f "$target" ]] && [[ "$(readlink "$target")" == "$source" ]]; then set_ownership_and_permissions "$target" - [[ "$DEBUG" == true ]] && echo "$target already linked to $source" + [[ "$DEBUG" == 1 ]] && echo "$target already linked to $source" return 1 else ln -sf "$source" "$target" \ @@ -62,7 +60,7 @@ function cleanup_links { symlinked_domain="${symlinked_domain%*.crt}" SYMLINKED_DOMAINS+=("$symlinked_domain") done - [[ "$DEBUG" == true ]] && echo "Symlinked domains: ${SYMLINKED_DOMAINS[*]}" + [[ "$DEBUG" == 1 ]] && echo "Symlinked domains: ${SYMLINKED_DOMAINS[*]}" # Create an array containing domains that are considered # enabled (ie present on /app/letsencrypt_service_data or /app/letsencrypt_user_data). @@ -77,7 +75,7 @@ function cleanup_links { ENABLED_DOMAINS+=("$domain") done done - [[ "$DEBUG" == true ]] && echo "Enabled domains: ${ENABLED_DOMAINS[*]}" + [[ "$DEBUG" == 1 ]] && echo "Enabled domains: ${ENABLED_DOMAINS[*]}" # Create an array containing only domains for which a symlinked private key exists # in /etc/nginx/certs but that no longer have a corresponding LETSENCRYPT_HOST set @@ -88,28 +86,28 @@ function cleanup_links { "${ENABLED_DOMAINS[@]}" \ | tr ' ' '\n' | sort | uniq -u) fi - [[ "$DEBUG" == true ]] && echo "Disabled domains: ${DISABLED_DOMAINS[*]}" + [[ "$DEBUG" == 1 ]] && echo "Disabled domains: ${DISABLED_DOMAINS[*]}" # Remove disabled domains symlinks if present. # Return 1 if nothing was removed and 0 otherwise. if [[ ${#DISABLED_DOMAINS[@]} -gt 0 ]]; then - [[ "$DEBUG" == true ]] && echo "Some domains are disabled :" + [[ "$DEBUG" == 1 ]] && echo "Some domains are disabled :" for disabled_domain in "${DISABLED_DOMAINS[@]}"; do - [[ "$DEBUG" == true ]] && echo "Checking domain ${disabled_domain}" - cert_folder="$(readlink -f /etc/nginx/certs/"${disabled_domain}".crt)" + [[ "$DEBUG" == 1 ]] && echo "Checking domain ${disabled_domain}" + cert_folder="$(readlink -f "/etc/nginx/certs/${disabled_domain}.crt")" # If the dotfile is absent, skip domain. if [[ ! -e "${cert_folder%/*}/.companion" ]]; then - [[ "$DEBUG" == true ]] && echo "No .companion file found in ${cert_folder}. ${disabled_domain} is not managed by letsencrypt-nginx-proxy-companion. Skipping domain." + [[ "$DEBUG" == 1 ]] && echo "No .companion file found in ${cert_folder}. ${disabled_domain} is not managed by letsencrypt-nginx-proxy-companion. Skipping domain." continue else - [[ "$DEBUG" == true ]] && echo "${disabled_domain} is managed by letsencrypt-nginx-proxy-companion. Removing unused symlinks." + [[ "$DEBUG" == 1 ]] && echo "${disabled_domain} is managed by letsencrypt-nginx-proxy-companion. Removing unused symlinks." fi for extension in .crt .key .dhparam.pem .chain.pem; do file="${disabled_domain}${extension}" if [[ -n "${file// }" ]] && [[ -L "/etc/nginx/certs/${file}" ]]; then - [[ "$DEBUG" == true ]] && echo "Removing /etc/nginx/certs/${file}" + [[ "$DEBUG" == 1 ]] && echo "Removing /etc/nginx/certs/${file}" rm -f "/etc/nginx/certs/${file}" fi done @@ -124,6 +122,7 @@ function update_certs { local -a LETSENCRYPT_CONTAINERS local -a LETSENCRYPT_STANDALONE_CERTS + pushd /etc/nginx/certs > /dev/null || return check_nginx_proxy_container_run || return # Load relevant container settings @@ -163,18 +162,10 @@ function update_certs { params_d_arr=() - # Use container's LETSENCRYPT_EMAIL if set, fallback to DEFAULT_EMAIL - email_varname="LETSENCRYPT_${cid}_EMAIL" - email_address="${!email_varname:-""}" - if [[ "$email_address" != "" ]]; then - params_d_arr+=(--email "$email_address") - elif [[ -n "${DEFAULT_EMAIL:-}" ]]; then - params_d_arr+=(--email "$DEFAULT_EMAIL") - fi - keysize_varname="LETSENCRYPT_${cid}_KEYSIZE" cert_keysize="${!keysize_varname:-""}" - if [[ "$cert_keysize" == "" ]]; then + if [[ "$cert_keysize" == "" ]] || \ + [[ ! "$cert_keysize" =~ ^(2048|3072|4096|8192|ec-256|ec-384)$ ]]; then cert_keysize=$DEFAULT_KEY_SIZE fi @@ -192,114 +183,61 @@ function update_certs { certificate_dir="/etc/nginx/certs/$base_domain" fi - account_varname="LETSENCRYPT_${cid}_ACCOUNT_ALIAS" - account_alias="${!account_varname:-""}" - if [[ "$account_alias" == "" ]]; then - account_alias=default + config_varname="LETSENCRYPT_${cid}_ACMESH_CONFIG" + config_name="${!config_varname:-""}" + if [[ "$config_name" == "" ]]; then + config_name=default + else + [[ ! -d "/etc/acme.sh/$config_name" ]] && mkdir -p "/etc/acme.sh/$config_name" fi - [[ "$DEBUG" == true ]] && params_d_arr+=(-v) - [[ $REUSE_PRIVATE_KEYS == true ]] && params_d_arr+=(--reuse_key) - [[ "${1}" == "--force-renew" ]] && params_d_arr+=(--valid_min 7776000) + [[ "$DEBUG" == 1 ]] && params_d_arr+=("--debug") + [[ "$RENEW_PRIVATE_KEYS" == true ]] && params_d_arr+=("--always-force-new-domain-key") + [[ "$1" == "--force-renew" ]] && params_d_arr+=("--force") - # Create directory for the first domain, - # make it root readable only and make it the cwd + # Create directory for the first domain mkdir -p "$certificate_dir" set_ownership_and_permissions "$certificate_dir" - pushd "$certificate_dir" || return for domain in "${!hosts_array}"; do # Add all the domains to certificate - params_d_arr+=(-d "$domain") + params_d_arr+=("--domain" "$domain") # Add location configuration for the domain add_location_configuration "$domain" || reload_nginx done - if [[ -e "./account_key.json" ]] && [[ ! -e "./account_reg.json" ]]; then - # If there is an account key present without account registration, this is - # a leftover from the ACME v1 version of simp_le. Remove this account key. - rm -f ./account_key.json - [[ "$DEBUG" == true ]] \ - && echo "Debug: removed ACME v1 account key $certificate_dir/account_key.json" - fi - - # The ACME account key and registration full path are derived from the - # endpoint URI + the account alias (set to 'default' if no alias is provided) - account_dir="../accounts/${acme_ca_uri#*://}" - if [[ $REUSE_ACCOUNT_KEYS == true ]]; then - for type in "key" "reg"; do - file_full_path="${account_dir}/${account_alias}_${type}.json" - simp_le_file="./account_${type}.json" - if [[ -f "$file_full_path" ]]; then - # If there is no symlink to the account file, create it - if [[ ! -L "$simp_le_file" ]]; then - ln -sf "$file_full_path" "$simp_le_file" \ - && set_ownership_and_permissions "$simp_le_file" - # If the symlink target the wrong account file, replace it - elif [[ "$(readlink -f "$simp_le_file")" != "$file_full_path" ]]; then - ln -sf "$file_full_path" "$simp_le_file" \ - && set_ownership_and_permissions "$simp_le_file" - fi - fi - done - fi - echo "Creating/renewal $base_domain certificates... (${hosts_array_expanded[*]})" - /usr/bin/simp_le \ - -f account_key.json -f account_reg.json \ - -f key.pem -f chain.pem -f fullchain.pem -f cert.pem \ - "${params_d_arr[@]}" \ - --cert_key_size="$cert_keysize" \ - --server="$acme_ca_uri" \ - --default_root /usr/share/nginx/html/ + acme.sh --issue \ + --log /dev/null \ + --config-home "/etc/acme.sh/$config_name" \ + "${params_d_arr[@]}" \ + --keylength "$cert_keysize" \ + --server "$acme_ca_uri" \ + --webroot /usr/share/nginx/html \ + --cert-file "${certificate_dir}/cert.pem" \ + --key-file "${certificate_dir}/key.pem" \ + --ca-file "${certificate_dir}/chain.pem" \ + --fullchain-file "${certificate_dir}/fullchain.pem" - simp_le_return=$? + acmesh_return=$? - if [[ $REUSE_ACCOUNT_KEYS == true ]]; then - mkdir -p "$account_dir" - for type in "key" "reg"; do - file_full_path="${account_dir}/${account_alias}_${type}.json" - simp_le_file="./account_${type}.json" - # If the account file to be reused does not exist yet, copy it - # from the CWD and replace the file in CWD with a symlink - if [[ ! -f "$file_full_path" && -f "$simp_le_file" ]]; then - cp "$simp_le_file" "$file_full_path" - ln -sf "$file_full_path" "$simp_le_file" - fi - done - fi - - popd || return - - if [[ $simp_le_return -ne 2 ]]; then + if [[ $acmesh_return -ne 2 ]]; then for domain in "${!hosts_array}"; do - if [[ "$acme_ca_uri" == "$le_staging_uri" ]]; then + if [[ $acme_ca_uri =~ ^https://acme-staging.* ]]; then create_links "_test_$base_domain" "$domain" && should_reload_nginx='true' && should_restart_container='true' else create_links "$base_domain" "$domain" && should_reload_nginx='true' && should_restart_container='true' fi done touch "${certificate_dir}/.companion" - # Set ownership and permissions of the files inside $certificate_dir - for file in .companion cert.pem key.pem chain.pem fullchain.pem account_key.json account_reg.json; do + set_ownership_and_permissions "${certificate_dir}/.companion" + # Make private key root readable only + for file in cert.pem key.pem chain.pem fullchain.pem; do file_path="${certificate_dir}/${file}" [[ -e "$file_path" ]] && set_ownership_and_permissions "$file_path" done - account_path="/etc/nginx/certs/accounts/${acme_ca_uri#*://}" - account_key_perm_path="${account_path}/${account_alias}_key.json" - account_reg_perm_path="${account_path}/${account_alias}_reg.json" - # Account key and registration files do not necessarily exists after - # simp_le exit code 1. Check if they exist before perm check (#591). - [[ -f "$account_key_perm_path" ]] && set_ownership_and_permissions "$account_key_perm_path" - [[ -f "$account_reg_perm_path" ]] && set_ownership_and_permissions "$account_reg_perm_path" - # Set ownership and permissions of the ACME account folder and its - # parent folders (up to /etc/nginx/certs/accounts included) - until [[ "$account_path" == /etc/nginx/certs ]]; do - set_ownership_and_permissions "$account_path" - account_path="$(dirname "$account_path")" - done # Queue nginx reload if a certificate was issued or renewed - [[ $simp_le_return -eq 0 ]] && should_reload_nginx='true' && should_restart_container='true' + [[ $acmesh_return -eq 0 ]] && should_reload_nginx='true' && should_restart_container='true' fi # Restart container if certs are updated and the respective environmental variable is set @@ -311,7 +249,7 @@ function update_certs { for domain in "${!hosts_array}"; do if [[ -f "/etc/nginx/conf.d/standalone-cert-$domain.conf" ]]; then - [[ $DEBUG == true ]] && echo "Debug: removing standalone configuration file /etc/nginx/conf.d/standalone-cert-$domain.conf" + [[ "$DEBUG" == 1 ]] && echo "Debug: removing standalone configuration file /etc/nginx/conf.d/standalone-cert-$domain.conf" rm -f "/etc/nginx/conf.d/standalone-cert-$domain.conf" && should_reload_nginx='true' fi done @@ -321,6 +259,8 @@ function update_certs { cleanup_links && should_reload_nginx='true' [[ "$should_reload_nginx" == 'true' ]] && reload_nginx + + popd > /dev/null || return } # Allow the script functions to be sourced without starting the Service Loop. diff --git a/app/letsencrypt_service_data.tmpl b/app/letsencrypt_service_data.tmpl index 9829586..a29c0a1 100644 --- a/app/letsencrypt_service_data.tmpl +++ b/app/letsencrypt_service_data.tmpl @@ -25,18 +25,16 @@ LETSENCRYPT_CONTAINERS=( {{ $host := trimSuffix "." $host }} {{ $hostHash := sha1 $host }} LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_HOST=('{{ $host }}') - LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}" LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}" LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}" - LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}" + LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_ACMESH_CONFIG="{{ $container.Env.LETSENCRYPT_ACMESH_CONFIG }}" LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}" {{ end }} {{ else }} LETSENCRYPT_{{ $cid }}_HOST=( {{ range $host := split $hosts "," }}{{ $host := trim $host }}{{ $host := trimSuffix "." $host }}'{{ $host }}' {{ end }}) - LETSENCRYPT_{{ $cid }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}" LETSENCRYPT_{{ $cid }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}" LETSENCRYPT_{{ $cid }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}" - LETSENCRYPT_{{ $cid }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}" + LETSENCRYPT_{{ $cid }}_ACMESH_CONFIG="{{ $container.Env.LETSENCRYPT_ACMESH_CONFIG }}" LETSENCRYPT_{{ $cid }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}" {{ end }} {{ end }} diff --git a/install_acme.sh b/install_acme.sh new file mode 100755 index 0000000..32a9c96 --- /dev/null +++ b/install_acme.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +# Install git (required to fetch acme.sh) +apk --update add git + +# Get acme.sh Let's Encrypt client source +tag="2.8.7" +mkdir /src +git -C /src clone https://github.com/Neilpang/acme.sh.git +cd /src/acme.sh +git checkout "$tag" + +# Install acme.sh in /app +./acme.sh --install \ + --nocron \ + --auto-upgrade 0 \ + --home /app \ + --config-home /etc/acme.sh/default + +# Make house cleaning +cd / +rm -rf /src +apk del git +rm -rf /var/cache/apk/* diff --git a/install_simp_le.sh b/install_simp_le.sh deleted file mode 100755 index ec0f1e6..0000000 --- a/install_simp_le.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -e - -# Install python and packages needed to build simp_le -apk add --update python3 git gcc musl-dev libffi-dev python3-dev openssl-dev - -# Create expected symlinks if they don't exist -[[ -e /usr/bin/pip ]] || ln -sf /usr/bin/pip3 /usr/bin/pip -[[ -e /usr/bin/python ]] || ln -sf /usr/bin/python3 /usr/bin/python - -# Get Let's Encrypt simp_le client source -branch="0.18.0" -mkdir -p /src -git -C /src clone --depth=1 --branch $branch https://github.com/zenhack/simp_le.git - -# Install simp_le in /usr/bin -cd /src/simp_le -#pip install wheel requests -for pkg in pip setuptools wheel -do - pip3 install -U "${pkg?}" -done -pip3 install . - -# Make house cleaning -cd / -rm -rf /src -apk del git gcc musl-dev libffi-dev python3-dev openssl-dev -rm -rf /var/cache/apk/* diff --git a/test/setup/setup-boulder.sh b/test/setup/setup-boulder.sh index a5388c7..861dd5b 100755 --- a/test/setup/setup-boulder.sh +++ b/test/setup/setup-boulder.sh @@ -12,12 +12,16 @@ setup_boulder() { pushd $GOPATH/src/github.com/letsencrypt/boulder git checkout release-2019-10-07 if [[ "$(uname)" == 'Darwin' ]]; then + # Set Standard Ports sed -i '' 's/ 5002/ 80/g' test/config/va.json sed -i '' 's/ 5001/ 443/g' test/config/va.json + # Modify custom rate limit sed -i '' 's/le.wtf,le1.wtf/le1.wtf,le2.wtf,le3.wtf/g' test/rate-limit-policies.yml else + # Set Standard Ports sed --in-place 's/ 5002/ 80/g' test/config/va.json sed --in-place 's/ 5001/ 443/g' test/config/va.json + # Modify custom rate limit sed --in-place 's/le.wtf,le1.wtf/le1.wtf,le2.wtf,le3.wtf/g' test/rate-limit-policies.yml fi docker-compose build --pull diff --git a/test/tests/certs_san/expected-std-out.txt b/test/tests/certs_san/expected-std-out.txt index 24be0a8..f35e28d 100644 --- a/test/tests/certs_san/expected-std-out.txt +++ b/test/tests/certs_san/expected-std-out.txt @@ -35,7 +35,7 @@ The correct certificate for le2.wtf was served by Nginx. le3.wtf is on certificate. Connection to le3.wtf using https was successful. The correct certificate for le3.wtf was served by Nginx. -Started test web server for le1.wtf.,le2.wtf.,le3.wtf +Started test web server for le1.wtf.,le3.wtf.,le2.wtf Symlink to le1.wtf certificate has been generated. The link is pointing to the file ./le1.wtf/fullchain.pem le1.wtf is on certificate. diff --git a/test/tests/certs_san/run.sh b/test/tests/certs_san/run.sh index 4b9efd7..cd3916c 100755 --- a/test/tests/certs_san/run.sh +++ b/test/tests/certs_san/run.sh @@ -21,7 +21,7 @@ function cleanup { i=$(( $i + 1 )) done # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } @@ -35,7 +35,7 @@ letsencrypt_hosts=( \ [0]="${domains[0]},${domains[1]},${domains[2]}" \ #straight comma separated list [1]="${domains[1]}, ${domains[2]}, ${domains[0]}" \ #comma separated list with spaces [2]="${domains[2]}, ${domains[0]}, ${domains[1]}," \ #comma separated list with spaces and a trailing comma - [3]="${domains[0]}.,${domains[1]}.,${domains[2]}" ) #trailing dots + [3]="${domains[0]}.,${domains[2]}.,${domains[1]}" ) #trailing dots i=1 @@ -94,7 +94,7 @@ for hosts in "${letsencrypt_hosts[@]}"; do done docker stop "$container" > /dev/null 2>&1 - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' i=$(( $i + 1 )) done diff --git a/test/tests/certs_single/run.sh b/test/tests/certs_single/run.sh index cf0ee32..cda7d89 100755 --- a/test/tests/certs_single/run.sh +++ b/test/tests/certs_single/run.sh @@ -19,7 +19,7 @@ function cleanup { docker rm --force "$domain" > /dev/null 2>&1 done # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } diff --git a/test/tests/certs_single_domain/run.sh b/test/tests/certs_single_domain/run.sh index d5402d6..f12a42f 100755 --- a/test/tests/certs_single_domain/run.sh +++ b/test/tests/certs_single_domain/run.sh @@ -21,7 +21,7 @@ function cleanup { i=$(( $i + 1 )) done # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } @@ -99,7 +99,7 @@ for hosts in "${letsencrypt_hosts[@]}"; do done docker stop "$container" > /dev/null 2>&1 - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' i=$(( $i + 1 )) done diff --git a/test/tests/certs_standalone/run.sh b/test/tests/certs_standalone/run.sh index c7d2da7..aa89268 100755 --- a/test/tests/certs_standalone/run.sh +++ b/test/tests/certs_standalone/run.sh @@ -17,7 +17,7 @@ function cleanup { # Remove the Nginx container silently. docker rm --force "$subdomain" > /dev/null 2>&1 # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } diff --git a/test/tests/container_restart/run.sh b/test/tests/container_restart/run.sh index e84cc9d..0bab1a9 100755 --- a/test/tests/container_restart/run.sh +++ b/test/tests/container_restart/run.sh @@ -29,7 +29,7 @@ function cleanup { docker rm --force "$domain" > /dev/null 2>&1 done # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } diff --git a/test/tests/force_renew/run.sh b/test/tests/force_renew/run.sh index 5ef116f..3d1aae5 100755 --- a/test/tests/force_renew/run.sh +++ b/test/tests/force_renew/run.sh @@ -17,7 +17,7 @@ function cleanup { # Remove the Nginx container silently. docker rm --force "${domains[0]}" > /dev/null 2>&1 # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } diff --git a/test/tests/permissions_custom/run.sh b/test/tests/permissions_custom/run.sh index dddfa55..eef4768 100755 --- a/test/tests/permissions_custom/run.sh +++ b/test/tests/permissions_custom/run.sh @@ -23,7 +23,7 @@ function cleanup { # Remove the ${domains[0]} Nginx container silently. docker rm --force "${domains[0]}" > /dev/null 2>&1 # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } @@ -41,10 +41,7 @@ wait_for_symlink "${domains[0]}" "$le_container_name" # Array of folder paths to test folders=( \ - [0]="/etc/nginx/certs/accounts" \ - [1]="/etc/nginx/certs/accounts/boulder:4001" \ - [2]="/etc/nginx/certs/accounts/boulder:4001/directory" \ - [3]="/etc/nginx/certs/${domains[0]}" \ + [0]="/etc/nginx/certs/${domains[0]}" \ ) # Test folder paths @@ -61,8 +58,6 @@ symlinks=( \ [1]="/etc/nginx/certs/${domains[0]}.key" \ [2]="/etc/nginx/certs/${domains[0]}.chain.pem" \ [3]="/etc/nginx/certs/${domains[0]}.dhparam.pem" \ - [4]="/etc/nginx/certs/${domains[0]}/account_key.json" \ - [5]="/etc/nginx/certs/${domains[0]}/account_reg.json" \ ) # Test symlinks paths @@ -76,9 +71,7 @@ symlinks=( \ # Array of private file paths to test private_files=( \ [0]="/etc/nginx/certs/default.key" \ - [1]="/etc/nginx/certs/accounts/boulder:4001/directory/default_key.json" \ - [2]="/etc/nginx/certs/accounts/boulder:4001/directory/default_reg.json" \ - [3]="/etc/nginx/certs/${domains[0]}/key.pem" \ + [1]="/etc/nginx/certs/${domains[0]}/key.pem" \ ) # Test private file paths diff --git a/test/tests/permissions_default/run.sh b/test/tests/permissions_default/run.sh index f440215..6a204a8 100755 --- a/test/tests/permissions_default/run.sh +++ b/test/tests/permissions_default/run.sh @@ -17,7 +17,7 @@ function cleanup { # Remove the ${domains[0]} Nginx container silently. docker rm --force "${domains[0]}" > /dev/null 2>&1 # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' # Stop the LE container docker stop "$le_container_name" > /dev/null } @@ -35,10 +35,7 @@ wait_for_symlink "${domains[0]}" "$le_container_name" # Array of folder paths to test folders=( \ - [0]="/etc/nginx/certs/accounts" \ - [1]="/etc/nginx/certs/accounts/boulder:4001" \ - [2]="/etc/nginx/certs/accounts/boulder:4001/directory" \ - [3]="/etc/nginx/certs/${domains[0]}" \ + [0]="/etc/nginx/certs/${domains[0]}" \ ) # Test folder paths @@ -55,8 +52,6 @@ symlinks=( \ [1]="/etc/nginx/certs/${domains[0]}.key" \ [2]="/etc/nginx/certs/${domains[0]}.chain.pem" \ [3]="/etc/nginx/certs/${domains[0]}.dhparam.pem" \ - [4]="/etc/nginx/certs/${domains[0]}/account_key.json" \ - [5]="/etc/nginx/certs/${domains[0]}/account_reg.json" \ ) # Test symlinks paths @@ -70,9 +65,7 @@ symlinks=( \ # Array of private file paths to test private_files=( \ [0]="/etc/nginx/certs/default.key" \ - [1]="/etc/nginx/certs/accounts/boulder:4001/directory/default_key.json" \ - [2]="/etc/nginx/certs/accounts/boulder:4001/directory/default_reg.json" \ - [3]="/etc/nginx/certs/${domains[0]}/key.pem" \ + [1]="/etc/nginx/certs/${domains[0]}/key.pem" \ ) # Test private file paths diff --git a/test/tests/symlinks/run.sh b/test/tests/symlinks/run.sh index 120a857..e6c5ddb 100755 --- a/test/tests/symlinks/run.sh +++ b/test/tests/symlinks/run.sh @@ -23,8 +23,8 @@ function cleanup { symlink-lim-le2 \ > /dev/null 2>&1 # Cleanup the files created by this run of the test to avoid foiling following test(s). - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*' - docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/lim.it*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf* && rm -rf /etc/acme.sh/default/le?.wtf*' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/lim.it* && rm -rf /etc/acme.sh/default/lim.it*' # Stop the LE container docker stop "$le_container_name" > /dev/null } diff --git a/test/tests/test-functions.sh b/test/tests/test-functions.sh index e81ca84..7fcebca 100755 --- a/test/tests/test-functions.sh +++ b/test/tests/test-functions.sh @@ -23,7 +23,7 @@ function run_le_container { --volume /var/run/docker.sock:/var/run/docker.sock:ro \ $cli_args \ --env "DHPARAM_BITS=256" \ - --env "DEBUG=true" \ + --env "DEBUG=2" \ --env "ACME_CA_URI=http://boulder:4001/directory" \ --label com.github.jrcs.letsencrypt_nginx_proxy_companion.test_suite \ --network boulder_bluenet \