diff --git a/README.md b/README.md index c05bbe66..4d413e30 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ It handles the automated creation, renewal and use of Let's Encrypt certificates for proxyed Docker containers. -Please note that [letsencrypt-nginx-proxy-companion does not work with ACME v2 endpoints yet](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion/issues/319). +Please note that **letsencrypt-nginx-proxy-companion** no longer supports ACME v1 endpoints. The last tagged version that supports ACME v1 is [v1.11](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion/releases/tag/v1.11.2). ### Features: * Automated creation/renewal of Let's Encrypt (or other ACME CAs) certificates using [**simp_le**](https://github.com/zenhack/simp_le). diff --git a/app/entrypoint.sh b/app/entrypoint.sh index c8a5cab1..9834b36e 100755 --- a/app/entrypoint.sh +++ b/app/entrypoint.sh @@ -135,10 +135,11 @@ function check_default_cert_key { source /app/functions.sh if [[ "$*" == "/bin/bash /app/start.sh" ]]; then - acmev2_re='https://acme-.*v02\.api\.letsencrypt\.org/directory' - if [[ "${ACME_CA_URI:-}" =~ $acmev2_re ]]; then - echo "Error: ACME v2 API is not yet supported by simp_le." - echo "See https://github.com/zenhack/simp_le/issues/101" + 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 fi check_docker_socket diff --git a/app/functions.sh b/app/functions.sh index 64ed07da..fe2d31bc 100644 --- a/app/functions.sh +++ b/app/functions.sh @@ -285,6 +285,8 @@ function set_ownership_and_permissions { return 1 fi + [[ "$(lc $DEBUG)" == true ]] && 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 user_num="$user" @@ -329,7 +331,7 @@ function set_ownership_and_permissions { fi # If the path is a file, check and modify permissions if required. elif [[ -f "$path" ]]; then - # Use different permissions for private files (private keys and ACME account keys) ... + # 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 [[ "$(lc $DEBUG)" == true ]] && echo "Debug: setting $path permissions to $f_perms." diff --git a/app/letsencrypt_service b/app/letsencrypt_service index 8f770347..d316251a 100755 --- a/app/letsencrypt_service +++ b/app/letsencrypt_service @@ -4,7 +4,7 @@ source /app/functions.sh seconds_to_wait=3600 -ACME_CA_URI="${ACME_CA_URI:-https://acme-v01.api.letsencrypt.org/directory}" +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})" @@ -158,7 +158,7 @@ function update_certs { fi test_certificate_varname="LETSENCRYPT_${cid}_TEST" - le_staging_uri="https://acme-staging.api.letsencrypt.org/directory" + le_staging_uri="https://acme-staging-v02.api.letsencrypt.org/directory" if [[ $(lc "${!test_certificate_varname:-}") == true ]] || \ [[ "$ACME_CA_URI" == "$le_staging_uri" ]]; then # Use staging Let's Encrypt ACME end point @@ -215,27 +215,39 @@ function update_certs { add_location_configuration "$domain" || reload_nginx done - # The ACME account key full path is derived from the endpoint URI - # + the account alias (set to 'default' if no alias is provided) - account_key_dir="../accounts/${acme_ca_uri#*://}" - account_key_full_path="${account_key_dir}/${account_alias}.json" + 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 + [[ "$(lc $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 - if [[ -f "$account_key_full_path" ]]; then - # If there is no symlink to the account key, create it - if [[ ! -L ./account_key.json ]]; then - ln -sf "$account_key_full_path" ./account_key.json \ - && set_ownership_and_permissions ./account_key.json - # If the symlink target the wrong account key, replace it - elif [[ "$(readlink -f ./account_key.json)" != "$account_key_full_path" ]]; then - ln -sf "$account_key_full_path" ./account_key.json \ - && set_ownership_and_permissions ./account_key.json + 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 - fi + done fi echo "Creating/renewal $base_domain certificates... (${hosts_array_expanded[*]})" /usr/bin/simp_le \ - -f account_key.json -f key.pem -f chain.pem -f fullchain.pem -f cert.pem \ + -f account_key.json -f account_reg.json \ + -f key.pem -f chain.pem -f fullchain.pem -f cert.pem \ $params_d_str \ --cert_key_size=$cert_keysize \ --server=$acme_ca_uri \ @@ -244,13 +256,17 @@ function update_certs { simp_le_return=$? if [[ $REUSE_ACCOUNT_KEYS == true ]]; then - # If the account key to be reused does not exist yet, copy it - # from the CWD and replace the file in CWD with a symlink - if [[ ! -f "$account_key_full_path" && -f ./account_key.json ]]; then - mkdir -p "$account_key_dir" - cp ./account_key.json "$account_key_full_path" - ln -sf "$account_key_full_path" ./account_key.json - fi + 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 @@ -262,20 +278,21 @@ function update_certs { else create_links "$base_domain" "$domain" && should_reload_nginx='true' && should_restart_container='true' fi - touch "${certificate_dir}/.companion" - set_ownership_and_permissions "${certificate_dir}/.companion" done - # Make private key root readable only - for file in cert.pem key.pem chain.pem fullchain.pem account_key.json; do + 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}/${file}" done - # Make the account key and its parent folders (up to - # /etc/nginx/certs/accounts included) root readable only - account_key_perm_path="/etc/nginx/certs/accounts/${acme_ca_uri#*://}/${account_alias}.json" + # Set ownership and permissions of the ACME account key and its parent + # folders (up to /etc/nginx/certs/accounts included) + account_key_perm_path="/etc/nginx/certs/accounts/${acme_ca_uri#*://}/${account_alias}_key.json" until [[ "$account_key_perm_path" == /etc/nginx/certs ]]; do set_ownership_and_permissions "$account_key_perm_path" account_key_perm_path="$(dirname "$account_key_perm_path")" done + # Set ownership and permissions of the ACME account registration + set_ownership_and_permissions "/etc/nginx/certs/accounts/${acme_ca_uri#*://}/${account_alias}_reg.json" # Queue nginx reload if a certificate was issued or renewed [[ $simp_le_return -eq 0 ]] && should_reload_nginx='true' && should_restart_container='true' fi diff --git a/install_simp_le.sh b/install_simp_le.sh index a527a4a8..b57e3809 100755 --- a/install_simp_le.sh +++ b/install_simp_le.sh @@ -10,7 +10,7 @@ apk add --update python3 git gcc musl-dev libffi-dev python3-dev openssl-dev [[ -e /usr/bin/python ]] || ln -sf /usr/bin/python3 /usr/bin/python # Get Let's Encrypt simp_le client source -branch="0.14.0" +branch="0.16.0" mkdir -p /src git -C /src clone --depth=1 --branch $branch https://github.com/zenhack/simp_le.git diff --git a/test/setup/setup-boulder.sh b/test/setup/setup-boulder.sh index 46cd8ba0..34604b29 100755 --- a/test/setup/setup-boulder.sh +++ b/test/setup/setup-boulder.sh @@ -2,7 +2,7 @@ set -e -acme_endpoint='http://boulder:4000/directory' +acme_endpoint='http://boulder:4001/directory' setup_boulder() { export GOPATH=${TRAVIS_BUILD_DIR}/go @@ -10,7 +10,7 @@ setup_boulder() { && git clone https://github.com/letsencrypt/boulder \ $GOPATH/src/github.com/letsencrypt/boulder pushd $GOPATH/src/github.com/letsencrypt/boulder - git checkout release-2019-06-17 + git checkout release-2019-10-07 if [[ "$(uname)" == 'Darwin' ]]; then # Set Standard Ports sed -i '' 's/ 5002/ 80/g' test/config/va.json diff --git a/test/tests/permissions_custom/run.sh b/test/tests/permissions_custom/run.sh index a43595be..dddfa55b 100755 --- a/test/tests/permissions_custom/run.sh +++ b/test/tests/permissions_custom/run.sh @@ -42,8 +42,8 @@ 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:4000" \ - [2]="/etc/nginx/certs/accounts/boulder:4000/directory" \ + [1]="/etc/nginx/certs/accounts/boulder:4001" \ + [2]="/etc/nginx/certs/accounts/boulder:4001/directory" \ [3]="/etc/nginx/certs/${domains[0]}" \ ) @@ -62,6 +62,7 @@ symlinks=( \ [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 @@ -75,8 +76,9 @@ symlinks=( \ # Array of private file paths to test private_files=( \ [0]="/etc/nginx/certs/default.key" \ - [1]="/etc/nginx/certs/accounts/boulder:4000/directory/default.json" \ - [2]="/etc/nginx/certs/${domains[0]}/key.pem" \ + [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" \ ) # Test private file paths @@ -89,11 +91,12 @@ done # Array of public files paths to test public_files=( \ - [0]="/etc/nginx/certs/${domains[0]}/cert.pem" \ - [1]="/etc/nginx/certs/${domains[0]}/chain.pem" \ - [2]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \ - [3]="/etc/nginx/certs/default.crt" \ - [4]="/etc/nginx/certs/dhparam.pem" \ + [0]="/etc/nginx/certs/${domains[0]}/.companion" \ + [1]="/etc/nginx/certs/${domains[0]}/cert.pem" \ + [2]="/etc/nginx/certs/${domains[0]}/chain.pem" \ + [3]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \ + [4]="/etc/nginx/certs/default.crt" \ + [5]="/etc/nginx/certs/dhparam.pem" \ ) # Test public file paths diff --git a/test/tests/permissions_default/run.sh b/test/tests/permissions_default/run.sh index 1e3ebea9..f4402159 100755 --- a/test/tests/permissions_default/run.sh +++ b/test/tests/permissions_default/run.sh @@ -36,8 +36,8 @@ 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:4000" \ - [2]="/etc/nginx/certs/accounts/boulder:4000/directory" \ + [1]="/etc/nginx/certs/accounts/boulder:4001" \ + [2]="/etc/nginx/certs/accounts/boulder:4001/directory" \ [3]="/etc/nginx/certs/${domains[0]}" \ ) @@ -56,6 +56,7 @@ symlinks=( \ [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 @@ -69,8 +70,9 @@ symlinks=( \ # Array of private file paths to test private_files=( \ [0]="/etc/nginx/certs/default.key" \ - [1]="/etc/nginx/certs/accounts/boulder:4000/directory/default.json" \ - [2]="/etc/nginx/certs/${domains[0]}/key.pem" \ + [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" \ ) # Test private file paths @@ -83,11 +85,12 @@ done # Array of public files paths to test public_files=( \ - [0]="/etc/nginx/certs/${domains[0]}/cert.pem" \ - [1]="/etc/nginx/certs/${domains[0]}/chain.pem" \ - [2]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \ - [3]="/etc/nginx/certs/default.crt" \ - [4]="/etc/nginx/certs/dhparam.pem" \ + [0]="/etc/nginx/certs/${domains[0]}/.companion" \ + [1]="/etc/nginx/certs/${domains[0]}/cert.pem" \ + [2]="/etc/nginx/certs/${domains[0]}/chain.pem" \ + [3]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \ + [4]="/etc/nginx/certs/default.crt" \ + [5]="/etc/nginx/certs/dhparam.pem" \ ) # Test public file paths diff --git a/test/tests/test-functions.sh b/test/tests/test-functions.sh index 6bda4531..308de6c4 100755 --- a/test/tests/test-functions.sh +++ b/test/tests/test-functions.sh @@ -24,7 +24,7 @@ function run_le_container { $cli_args \ --env "DHPARAM_BITS=256" \ --env "DEBUG=true" \ - --env "ACME_CA_URI=http://boulder:4000/directory" \ + --env "ACME_CA_URI=http://boulder:4001/directory" \ --label com.github.jrcs.letsencrypt_nginx_proxy_companion.test_suite \ --network boulder_bluenet \ "$image" > /dev/null && echo "Started letsencrypt container for test ${name%%_2*}"